package  com.sat.common.base

import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LifecycleObserver
import androidx.lifecycle.viewModelScope
import  com.sat.common.bean.Message
import  com.sat.common.network.ExceptionHandle
import  com.sat.common.network.ResponseResult
import  com.sat.common.network.ResponseThrowable
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.launch

/**
 *   @auther : Aleyn
 *   time   : 2019/11/01
 */
open class BaseViewModel : AndroidViewModel(BaseAPP.getInstance()), LifecycleObserver {

    val defUI: UIChange by lazy { UIChange() }

    /**
     * 用流的方式进行网络请求
     */
    fun <T> launchFlow(block: suspend () -> T): Flow<T> {
        return flow {
            emit(block())
        }
    }

    /**
     *  返回自定义格式的请求
     * @param block 请求体
     * @param error 失败回调
     * @param success 成功回调
     * @param complete  完成回调（无论成功失败都会调用）
     * @param isShowDialog 是否显示加载框
     */
    fun <T> launchGoCustom(
        block: suspend () -> T,
        error: (ResponseThrowable) -> Unit = {
            defUI.toastEvent.postValue("${it.errMsg}")
        },
        success: (T) -> Unit = {},
        complete: () -> Unit = {},
        isShowDialog: Boolean = true
    ) {
        if (isShowDialog) defUI.showDialog.call()
        customHandleException(
            block,
            { res ->
                executeCustomResponse(res, success)
            },
            { error(it) },
            {
                if (isShowDialog)
                    defUI.dismissDialog.call()
                complete()
            }
        )
    }


    /**
     * 返回符合接口返回统一格式规范的请求
     * @param block 请求体
     * @param success 成功回调
     * @param error 失败回调
     * @param complete  完成回调（无论成功失败都会调用）
     * @param isShowDialog 是否显示加载框
     */
    fun <T> launchCommon(
        block: suspend () -> ResponseResult<T>,
        success: (T) -> Unit,
        isShowTip: Boolean = true,
        error: (ResponseThrowable) -> Unit = {
            it.printStackTrace()
            if (isShowTip)
                defUI.toastEvent.postValue("${it.code}:${it.errMsg}")
        },
        complete: () -> Unit = {},
        isShowDialog: Boolean = true,
    ) {
        if (isShowDialog) defUI.showDialog.call()
        commonHandleException(
            block,
            { res ->
                executeCommonResponse(res) { success(it) }
            },
            {
                it.printStackTrace()
                error(it)
            },
            {
                if (isShowDialog)
                    defUI.dismissDialog.call()
                complete()
            }
        )

    }

    fun <T> launchCommon(
        block: suspend () -> ResponseResult<T>,
        success: (T) -> Unit,
        error: (ResponseThrowable) -> Unit,
        complete: () -> Unit = {},
        isShowDialog: Boolean = true,
    ) {
        launchCommon(block, success, true, error, complete, isShowDialog)
    }

    /**
     * 统一结果请求结果过滤
     */
    private fun <T> executeCommonResponse(
        response: ResponseResult<T>,
        success: (T) -> Unit
    ) {
        if (response.code == 200) success(response.data)
        else throw ResponseThrowable(
            response.code,
            response.message
        )
    }

    /**
     * 自定义结果请求结果过滤
     */
    private fun <T> executeCustomResponse(
        response: T,
        success: (T) -> Unit
    ) {

        success(response)

    }

    /**
     * 异常统一处理
     */
    private fun <T> commonHandleException(
        block: suspend () -> ResponseResult<T>,
        success: (ResponseResult<T>) -> Unit,
        error: (ResponseThrowable) -> Unit,
        complete: () -> Unit
    ) {
        viewModelScope.launch {
            try {
                success(block())
            } catch (e: Throwable) {
                error(ExceptionHandle.handleException(e))
            } finally {
                complete()
            }
        }
    }


    /**
     * 自定义返回结果的异常统一处理
     */
    private fun <T> customHandleException(
        block: suspend () -> T,
        success: (T) -> Unit,
        error: (ResponseThrowable) -> Unit,
        complete: () -> Unit
    ) {
        viewModelScope.launch {
            try {
                success(block())
            } catch (e: Throwable) {
                e.printStackTrace()
                error(ExceptionHandle.handleException(e))
            } finally {
                complete()
            }
        }

    }


    /**
     * @param resId 字符串资源id
     * @return 返回资源id的字符串内容
     */
    fun getString(resId: Int): String {
        return getApplication<BaseAPP>().resources.getString(resId);
    }


    /**
     * UI事件
     */
    inner class UIChange {
        val showDialog by lazy { SingleLiveEvent<String?>() }
        val dismissDialog by lazy { SingleLiveEvent<Void?>() }
        val toastEvent by lazy { SingleLiveEvent<String>() }
        val msgEvent by lazy { SingleLiveEvent<Message>() }
    }
}